using System.ComponentModel;
using System.Reflection.Metadata.Ecma335;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;

namespace OllamaProxy
{
    public class Program
    {

        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // 配置全局 JSON 序列化选项
            builder.Services.ConfigureHttpJsonOptions(options =>
            {
                options.SerializerOptions.IncludeFields = true;
                options.SerializerOptions.PropertyNamingPolicy = null; // 支持公有属性输出
                options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; // 可选：忽略 null 值
                options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
            });

            // 读取ollama配置
            OllamaConfig config = builder.Configuration.GetSection("OllamaConfig").Get<OllamaConfig>();
            if(config==null) config=new OllamaConfig();

            // 注册 HttpClient 并全局禁用代理
            builder.Services.AddHttpClient("ollama",client=>{
                client.Timeout = TimeSpan.FromSeconds(300);
                client.BaseAddress = new Uri(config.base_url);
            }).ConfigurePrimaryHttpMessageHandler(() =>
            {
                // 创建 HttpClientHandler 并禁用代理
                return new HttpClientHandler
                {
                    UseProxy = false // 禁用代理
                };
            });

            var app = builder.Build();

            // 添加OpenAI API Endpoints
            var openaiApi = app.MapGroup("/");

            openaiApi.MapGet("/", async (IHttpClientFactory httpClientFactory) =>
            {
                try
                {
                    var httpClient = httpClientFactory.CreateClient("ollama");
                    var response = await httpClient.GetAsync("/");
                    response.EnsureSuccessStatusCode();
                    var content = await response.Content.ReadAsStringAsync();
                    return Results.Content(content);
                }
                catch (Exception ex)
                {
                    return Results.Problem(ex.Message);
                }
            });

            openaiApi.MapGet("/v1/models", async (IHttpClientFactory httpClientFactory) =>
            {
                try
                {
                    var httpClient = httpClientFactory.CreateClient("ollama");
                    var response = await httpClient.GetAsync("/api/tags");
                    response.EnsureSuccessStatusCode();
                    var content = await response.Content.ReadAsStringAsync();
                    var res=JsonSerializer.Deserialize<JsonElement>(content,AppJsonSerializerContext.Default.JsonElement);
                    var res2=new ModelListResponse(res);
                    return Results.Ok(res2);
                }
                catch (Exception ex)
                {
                    return Results.Problem(ex.Message);
                }
            });

            openaiApi.MapGet("/v1/models/{model_id}", async (string model_id, IHttpClientFactory httpClientFactory) =>
            {
                 try
                {
                    var httpClient = httpClientFactory.CreateClient("ollama");
                    var response = await httpClient.GetAsync("/api/tags");
                    response.EnsureSuccessStatusCode();
                    var content = await response.Content.ReadAsStringAsync();
                    var res=JsonSerializer.Deserialize<JsonElement>(content,AppJsonSerializerContext.Default.JsonElement);
                    foreach(var m in res.GetProperty("models").EnumerateArray())
                        if(m.GetProperty("model").GetString() == model_id)
                            return Results.Ok(m);
                    return Results.Ok(ErrorResponse.create("model '"+model_id+"' not found"));
                    
                }
                catch (Exception ex)
                {
                    return Results.Problem(ex.Message);
                }
            });

            openaiApi.MapPost("/v1/completions", (JsonNode request) =>
            {
                return Results.Ok(ErrorResponse.create("not implemented"));
            });

            openaiApi.MapPost("/v1/chat/completions", async ([FromBody] JsonElement request, IHttpClientFactory httpClientFactory) =>
            {

                var httpClient = httpClientFactory.CreateClient("ollama");
                OllamaChatCompeltionsRequest req=new OllamaChatCompeltionsRequest(request);
                string json=JsonSerializer.Serialize(req,AppJsonSerializerContext.Default.OllamaChatCompeltionsRequest);
                var response = await httpClient.PostAsJsonAsync<OllamaChatCompeltionsRequest>("/api/chat",req,AppJsonSerializerContext.Default.OllamaChatCompeltionsRequest);
                response.EnsureSuccessStatusCode();
                var content = await response.Content.ReadAsStringAsync();
                var res=JsonSerializer.Deserialize<JsonElement>(content,AppJsonSerializerContext.Default.JsonElement);
                return Results.Ok(res);
            });

            openaiApi.MapPost("/v1/embeddings", (JsonNode request) =>
            {
                // 示例：提取一些字段
                var model = request["model"]?.GetValue<string>();
                var input = request["input"];  //string[] or string

                var obj=new JsonObject();
                obj["model"]=model;

                if(input!=null) {
                    JsonValueKind kind=input.GetValueKind();
                    if(kind==JsonValueKind.Array)
                        obj.Add("input",input.DeepClone());
                    else if(kind==JsonValueKind.String)
                        obj["input"]=input.GetValue<string>();
                }
                
                return Results.Ok(obj);
            });

            // 启动应用并保持运行
            app.Run();
        }
    }
    
    

}